Skip to content

在上篇中,我们介绍了 JIT 模式的基本概念和工作原理。本篇将通过一个简单的例子来展示如何在实际项目中实现 JIT 模式。通过实现一个简单的 JIT 编译器,我们可以更深入地理解其原理和实现方式。

1. 简单 JIT 模式的核心思想

JIT 模式的核心思想是 按需生成和优化资源。与传统的静态编译模式相比,JIT 仅在需要时才生成资源,而不是预先编译所有内容。

为了实现一个简单的 JIT,我们的目标是:

  • 按需生成:仅在用户或应用请求时生成资源,而不是一次性生成所有的资源。
  • 动态生成:生成的资源(如 CSS 样式)会在运行时被动态地注入到页面或应用中。

2. 设计思路:一个简单的 JIT CSS 生成器

假设我们要实现一个简单的 JIT CSS 生成器,它可以根据页面中的动态类名来生成对应的 CSS 规则。我们将实现以下功能:

  • 生成动态样式:当我们使用动态类名时,JIT 编译器会实时生成对应的 CSS 样式。
  • 缓存已生成的样式:为了避免重复生成相同的样式,我们将使用缓存机制来保存已经生成的规则。
  • 按需插入样式:生成的样式会立即插入到页面中的 <style> 标签中,而不是等待整个文件的构建。

3. 代码实现

下面是一个简单的 JIT CSS 生成器实现:

3.1. JIT CSS 类

javascript
class JITCSS {
  constructor() {
    this.styleSheet = document.createElement('style'); // 创建 style 元素
    document.head.appendChild(this.styleSheet); // 将其添加到页面 head 中
    this.generatedClasses = new Map(); // 用 Map 缓存样式,避免重复生成
  }

  // 生成并注入 CSS 样式
  generateCSS(className, styles) {
    if (this.generatedClasses.has(className)) return; // 如果已生成,则跳过

    let rule = `.${className} { `; // 修正为以 . 开头
    for (let [property, value] of Object.entries(styles)) {
      // 确保属性名符合 CSS 的规范(使用短横线分隔)
      let cssProperty = property.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
      rule += `${cssProperty}: ${value}; `;
    }
    rule += '}';

    // 插入生成的 CSS 规则
    this.styleSheet.textContent += rule;
    this.generatedClasses.set(className, styles); // 缓存已生成的类
  }

  // 应用样式类
  applyClass(element, className, styles) {
    this.generateCSS(className, styles); // 动态生成 CSS
    element.classList.add(className); // 应用样式类
  }
}

// 创建 JIT CSS 实例
const jit = new JITCSS();
const box = document.createElement('div');
document.body.appendChild(box);

// 应用动态样式类
jit.applyClass(box, 'dynamic-box', {
  width: '200px',
  height: '200px',
  position: 'fixed',
  top: '20%',
  left: '20%',
  backgroundColor: 'rgb(255,0,0)',
  borderRadius: '10px',
  display: 'block', // 确保 div 是可见的块级元素
});

// 2秒后应用另一种动态样式
setTimeout(() => {
  jit.applyClass(box, 'dynamic-box-2', {
    backgroundColor: 'rgb(0,255,0)',
  });
}, 2000);

3.2. 代码解析

  • JITCSS 类: 我们创建了一个 JITCSS 类,该类负责管理 CSS 样式的生成和应用。它包括生成样式的逻辑、缓存机制以及将样式动态插入页面的功能。
  • generateCSS 方法: 此方法用于动态生成 CSS 规则并插入到页面的 <style> 标签中。我们使用 Map 来缓存已经生成的样式类,避免重复生成。
  • applyClass 方法: 当需要在元素上应用新的样式时,调用此方法,首先检查是否已经生成该样式规则,如果没有,则生成它。

3.3. 动态应用样式

在上面的代码中,我们首先通过 jit.applyClass() 方法应用了一个名为 dynamic-box 的样式类,并在 2 秒后动态应用了另一种样式 dynamic-box-2。这些样式是根据提供的参数动态生成的,而不需要预先编写完整的 CSS 文件。

3.4. 文件监听

如果你在一个构建工具(比如 Webpack)中使用 JIT 模式,通常你需要在 Node.js 环境中进行文件监听。你可以使用 fs.watch 来实现。

示例:使用 fs.watch 监听文件变化并生成新的 CSS

javascript
const fs = require('fs');
const path = require('path');

// 文件监听路径
const watchPath = path.join(__dirname, 'src/styles'); // 这里假设样式文件保存在 src/styles 目录下

fs.watch(watchPath, (eventType, filename) => {
  if (filename && eventType === 'change') {
    console.log(`File changed: ${filename}`);
    // 假设在文件变化时重新生成 JIT 样式
    // 这里可以调用你的 JIT 生成逻辑
    // 确保 jit 实例调用方法
    jit.generateCSSFromFile(filename);
  }
});

同时需要在JITCSS类加入响应函数

javascript
generateCSSFromFile(filename) {
  // 读取文件内容并生成 CSS(简单示例)
  const content = fs.readFileSync(path.join(watchPath, filename), 'utf-8');
  // 假设内容为 JSON 格式的样式对象
  const styles = JSON.parse(content);
  Object.keys(styles).forEach(className => {
    this.generateCSS(className, styles[className]);
  });
};

3.5. DOM变更监听

在一些动态网页中,元素的类名或样式可能会在用户交互后发生变化,此时使用 MutationObserver 可以实时监听这些变化并应用新的 JIT 样式。

示例:使用 MutationObserver 监听 DOM 变动并应用新的样式

javascript
// JITCSS类加入 DOM 变更监听
observeDOMChanges(targetElement) {
    const observer = new MutationObserver(mutations => {
      mutations.forEach(mutation => {
        // 当目标元素的 class 或 style 改变时执行的操作
        if (mutation.type === 'attributes' && (mutation.attributeName === 'class' || mutation.attributeName === 'style')) {
          console.log(`Attribute changed: ${mutation.attributeName}`);
          // 这里可以调用生成新的 JIT 样式的逻辑
        }
      });
    });

    observer.observe(targetElement, {
      attributes: true, // 监听属性变化
      childList: false, // 不监听子节点变化
      subtree: false, // 不监听子树
    });
}

4. 小结

本篇文章通过实现一个简单的 JIT CSS 生成器,帮助更好地理解 JIT 模式的工作原理。

在实际项目中,JIT 模式可以有效地减少冗余样式、优化页面性能,并提升开发效率。

尽管 JIT 模式可以显著优化性能,但在资源频繁变更的场景中,可能导致不必要的开销。因此,建议在动态性较高的项目中使用,同时结合缓存机制减少性能损耗。

上次更新于: